package services

import (
	"context"
	"errors"
	"go-mp-starter/app/common/request"
	"go-mp-starter/app/models"
	"go-mp-starter/global"
	"path"
	"strconv"
	"time"

	"github.com/jassue/go-storage/storage"
	uuid "github.com/satori/go.uuid"
	"go.uber.org/zap"
)

type mediaService struct{}

const mediaCachePrefix = "media:"

var MediaService = new(mediaService)

type outPut struct {
	Id   int64  `json:"id"`
	Path string `json:"path"`
	Url  string `json:"url"`
}

// 返回文件储存目录
func (mds *mediaService) makeFaceDir(business string) string {
	return global.App.Config.App.Env + "/" + business
}

// HashName 生成文件名称(使用 uuid)
func (mds *mediaService) HashName(filename string) string {
	fileSuffix := path.Ext(filename)
	return uuid.NewV4().String() + fileSuffix
}

// SaveImage 保存图片
func (mds *mediaService) SaveImage(params request.ImageUpload) (res outPut, err error) {
	file, err := params.Image.Open()
	if err != nil {
		err = errors.New("获取文件失败")
		global.App.Log.Error("open file fail", zap.Any("err", err))
		return
	}
	defer file.Close()

	localPrefix := ""
	// 存放路径: ./storage/app/public
	// 已配置路由 router.Static("/storage", "./storage/app/public")
	if global.App.Config.Storage.Default == storage.Local {
		localPrefix = "public/"
	}
	// 按业务类型建一个同名目录存放文件
	key := mds.makeFaceDir(params.Business) + "/" + mds.HashName(params.Image.Filename)
	disk := global.App.Disk()
	err = disk.Put(localPrefix+key, file, params.Image.Size)
	if err != nil {
		global.App.Log.Error("put file fail", zap.Any("err", err))
		err = errors.New("文件上传失败")
		return
	}

	// 文件信息入库 Media
	img := models.Media{
		DiskType: string(global.App.Config.Storage.Default),
		SrcType:  1,
		Src:      key,
	}
	err = global.App.DB.Create(&img).Error
	if err != nil {
		global.App.Log.Error("save to db fail", zap.Any("err", err))
		err = errors.New("文件入库失败")
		return
	}

	res = outPut{int64(img.ID.ID), key, disk.Url(key)}
	return
}

// GetUrlById 通过Id获取文件url
func (mds *mediaService) GetUrlById(id int64) (url string) {
	if id == 0 {
		return ""
	}
	// 从缓存中获取
	cacheKey := mediaCachePrefix + strconv.FormatInt(id, 10)

	exist := global.App.Redis.Exists(context.Background(), cacheKey).Val()
	if exist == 1 {
		url = global.App.Redis.Get(context.Background(), cacheKey).Val()
	} else {
		media := models.Media{}
		err := global.App.DB.First(&media, id).Error
		if err != nil {
			return ""
		}
		url = global.App.Disk(media.DiskType).Url(media.Src)
		// 设置缓存
		global.App.Redis.Set(context.Background(), cacheKey, url, 3*24*3600*time.Second)
	}

	return
}
